/*
 * Copyright (c) 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */
package java.lang.reflect;

import java.lang.annotation.*;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import sun.reflect.annotation.AnnotationSupport;

/**
 * 关于方法参数的信息。
 *
 * {@code Parameter} 提供关于方法参数的信息，包括其名称和修饰符。
 * 它还提供了获取参数属性的替代方法。
 *
 * @since 1.8
 */
public final class Parameter implements AnnotatedElement {

    private final String name;
    private final int modifiers;
    private final Executable executable;
    private final int index;

    /**
     * {@code Parameter} 的包私有构造函数。
     *
     * 如果类文件中存在方法参数数据，则 JVM 直接创建 {@code Parameter} 对象。
     * 但是，如果不存在，则 {@code Executable} 使用此构造函数来合成它们。
     *
     * @param name 参数的名称
     * @param modifiers 参数的修饰符标志
     * @param executable 定义此参数的可执行元素
     * @param index 参数的索引
     */
    Parameter(String name,
              int modifiers,
              Executable executable,
              int index) {
        this.name = name;
        this.modifiers = modifiers;
        this.executable = executable;
        this.index = index;
    }

    /**
     * 基于可执行元素和索引进行比较。
     *
     * @param obj 要比较的对象
     * @return 此对象是否等于参数
     */
    public boolean equals(Object obj) {
        if(obj instanceof Parameter) {
            Parameter other = (Parameter)obj;
            return (other.executable.equals(executable) &&
                    other.index == index);
        }
        return false;
    }

    /**
     * 返回基于可执行元素的哈希码和索引的哈希码。
     *
     * @return 基于可执行元素哈希码的哈希码
     */
    public int hashCode() {
        return executable.hashCode() ^ index;
    }

    /**
     * 如果根据类文件参数有名称，则返回 true；否则返回 false。
     * 参数是否有名称由声明该参数的方法的 {@literal MethodParameters} 属性确定。
     *
     * @return 当且仅当根据类文件参数有名称时返回 true
     */
    public boolean isNamePresent() {
        return executable.hasRealParameterData() && name != null;
    }

    /**
     * 返回描述此参数的字符串。格式是参数的修饰符（如果有的话），
     * 按照 <cite>The Java&trade; Language Specification</cite> 推荐的规范顺序，
     * 然后是参数的完全限定类型（如果参数是可变参数，则排除最后的 []），
     * 如果参数是可变参数则跟随 "..."，然后是一个空格，最后是参数的名称。
     *
     * @return 参数及相关信息的字符串表示
     */
    public String toString() {
        final StringBuilder sb = new StringBuilder();
        final Type type = getParameterizedType();
        final String typename = type.getTypeName();

        sb.append(Modifier.toString(getModifiers()));

        if(0 != modifiers)
            sb.append(' ');

        if(isVarArgs())
            sb.append(typename.replaceFirst("\\[\\]$", "..."));
        else
            sb.append(typename);

        sb.append(' ');
        sb.append(getName());

        return sb.toString();
    }

    /**
     * 返回声明此参数的 {@code Executable}。
     *
     * @return 声明此参数的 {@code Executable}
     */
    public Executable getDeclaringExecutable() {
        return executable;
    }

    /**
     * 获取此 {@code Parameter} 对象所代表的参数的修饰符标志。
     *
     * @return 此参数的修饰符标志
     */
    public int getModifiers() {
        return modifiers;
    }

    /**
     * 返回参数的名称。如果参数的名称{@linkplain #isNamePresent() 存在}，
     * 则此方法返回类文件提供的名称。否则，此方法合成一个形式为 argN 的名称，
     * 其中 N 是参数在声明该参数的方法描述符中的索引。
     *
     * @return 参数的名称，由类文件提供或在类文件不提供名称时合成
     */
    public String getName() {
        // Note: empty strings as paramete names are now outlawed.
        // The .equals("") is for compatibility with current JVM
        // behavior.  It may be removed at some point.
        if(name == null || name.equals(""))
            return "arg" + index;
        else
            return name;
    }

    // Package-private accessor to the real name field.
    String getRealName() {
        return name;
    }

    /**
     * 返回一个 {@code Type} 对象，该对象标识此 {@code Parameter} 对象
     * 所代表的参数的参数化类型。
     *
     * @return 标识此对象所代表的参数的参数化类型的 {@code Type} 对象
     */
    public Type getParameterizedType() {
        Type tmp = parameterTypeCache;
        if (null == tmp) {
            tmp = executable.getAllGenericParameterTypes()[index];
            parameterTypeCache = tmp;
        }

        return tmp;
    }

    private transient volatile Type parameterTypeCache = null;

    /**
     * 返回一个 {@code Class} 对象，该对象标识此 {@code Parameter} 对象
     * 所代表的参数的声明类型。
     *
     * @return 标识此对象所代表的参数的声明类型的 {@code Class} 对象
     */
    public Class<?> getType() {
        Class<?> tmp = parameterClassCache;
        if (null == tmp) {
            tmp = executable.getParameterTypes()[index];
            parameterClassCache = tmp;
        }
        return tmp;
    }

    /**
     * 返回一个 AnnotatedType 对象，该对象表示使用类型来指定此 Parameter
     * 所代表的形式参数的类型。
     *
     * @return 表示使用类型来指定此 Parameter 所代表的形式参数类型的
     *         {@code AnnotatedType} 对象
     */
    public AnnotatedType getAnnotatedType() {
        // no caching for now
        return executable.getAnnotatedParameterTypes()[index];
    }

    private transient volatile Class<?> parameterClassCache = null;

    /**
     * 如果此参数在源代码中是隐式声明的，则返回 {@code true}；否则返回 {@code false}。
     *
     * @return 当且仅当此参数按照 <cite>The Java&trade; Language Specification</cite>
     *         定义的隐式声明时返回 true
     */
    public boolean isImplicit() {
        return Modifier.isMandated(getModifiers());
    }

    /**
     * 如果此参数在源代码中既不是隐式声明也不是显式声明的，则返回 {@code true}；
     * 否则返回 {@code false}。
     *
     * @jls 13.1 The Form of a Binary
     * @return 当且仅当此参数是按照 <cite>The Java&trade; Language Specification</cite>
     *         定义的合成构造时返回 true
     */
    public boolean isSynthetic() {
        return Modifier.isSynthetic(getModifiers());
    }

    /**
     * 如果此参数表示可变参数列表，则返回 {@code true}；否则返回 {@code false}。
     *
     * @return 当且仅当此参数表示可变参数列表时返回 {@code true}
     */
    public boolean isVarArgs() {
        return executable.isVarArgs() &&
            index == executable.getParameterCount() - 1;
    }


    /**
     * 返回此元素上存在的指定类型的注解，如果没有此类型的注解则返回 null。
     *
     * @param <T> 要查询并返回的注解类型（如果存在）
     * @param annotationClass 对应于注解类型的 Class 对象
     * @return 此元素上存在的指定注解类型的注解，如果没有此类型的注解则返回 null
     * @throws NullPointerException 如果给定的注解类为 null
     */
    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
        Objects.requireNonNull(annotationClass);
        return annotationClass.cast(declaredAnnotations().get(annotationClass));
    }

    /**
     * 返回与此元素关联的指定类型的注解。
     *
     * 如果没有与此元素关联的指定类型的注解，则返回值是一个长度为 0 的数组。
     * 此方法与 {@link #getDeclaredAnnotationsByType(Class)} 的区别在于，
     * 此方法会搜索其超类以查找可继承的注解。
     *
     * @param <T> 要查询并返回的注解类型（如果存在）
     * @param annotationClass 对应于注解类型的 Class 对象
     * @return 与此元素关联的指定类型的所有注解，如果没有关联的注解则返回长度为 0 的数组
     * @throws NullPointerException 如果给定的注解类为 null
     */
    @Override
    public <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
        Objects.requireNonNull(annotationClass);

        return AnnotationSupport.getDirectlyAndIndirectlyPresent(declaredAnnotations(), annotationClass);
    }

    /**
     * 返回直接存在于此元素上的注解。
     *
     * 此方法忽略继承的注解。如果没有注解直接存在于此元素上，
     * 则返回值是一个长度为 0 的数组。
     * 此方法的调用者可以自由修改返回的数组；这不会对返回给其他调用者的数组产生影响。
     *
     * @return 直接存在于此元素上的注解
     */
    public Annotation[] getDeclaredAnnotations() {
        return executable.getParameterAnnotations()[index];
    }

    /**
     * 返回直接存在于此元素上的指定类型的注解，如果没有此类型的注解则返回 null。
     *
     * 此方法忽略继承的注解。（如果没有注解直接存在于此元素上，则返回 null。）
     *
     * @param <T> 要查询并返回的注解类型（如果直接存在）
     * @param annotationClass 对应于注解类型的 Class 对象
     * @return 直接存在于此元素上的指定注解类型的注解，如果没有此类型的注解则返回 null
     * @throws NullPointerException 如果给定的注解类为 null
     */
    public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
        // Only annotations on classes are inherited, for all other
        // objects getDeclaredAnnotation is the same as
        // getAnnotation.
        return getAnnotation(annotationClass);
    }

    /**
     * 返回直接存在于此元素上的指定类型的注解。
     *
     * 此方法忽略继承的注解。如果没有指定类型的注解直接存在于此元素上，
     * 则返回值是一个长度为 0 的数组。
     *
     * @param <T> 要查询并返回的注解类型（如果直接存在）
     * @param annotationClass 对应于注解类型的 Class 对象
     * @return 直接存在于此元素上的指定类型的所有注解，如果没有此类型的注解则返回长度为 0 的数组
     * @throws NullPointerException 如果给定的注解类为 null
     */
    @Override
    public <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
        // Only annotations on classes are inherited, for all other
        // objects getDeclaredAnnotations is the same as
        // getAnnotations.
        return getAnnotationsByType(annotationClass);
    }

    /**
     * 返回此元素上存在的所有注解。
     * 如果此元素没有注解，则返回值是一个长度为 0 的数组。
     * 此方法的调用者可以自由修改返回的数组；这不会对返回给其他调用者的数组产生影响。
     *
     * @return 此元素上存在的所有注解
     */
    public Annotation[] getAnnotations() {
        return getDeclaredAnnotations();
    }

    private transient Map<Class<? extends Annotation>, Annotation> declaredAnnotations;

    private synchronized Map<Class<? extends Annotation>, Annotation> declaredAnnotations() {
        if(null == declaredAnnotations) {
            declaredAnnotations =
                new HashMap<Class<? extends Annotation>, Annotation>();
            Annotation[] ann = getDeclaredAnnotations();
            for(int i = 0; i < ann.length; i++)
                declaredAnnotations.put(ann[i].annotationType(), ann[i]);
        }
        return declaredAnnotations;
   }

}
